package conf

import (
	"fmt"
	"sync"

	"github.com/gin-contrib/cors"
	"github.com/gin-gonic/gin"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
)

func Default() *Config {
	return &Config{
		MySQL: &mySQL{
			Host:     "127.0.0.1",
			Port:     3306,
			Username: "root",
			Password: "123456",
			DB:       "vblog01",
			Debug:    true,
		},
		Application: &appliction{
			Host:   "127.0.0.1",
			Port:   9999,
			Domain: "http://127.0.0.1",
		},
	}
}

type Config struct {
	MySQL       *mySQL      `json:"mysql" yaml:"mysql" toml:"mysql"`
	Application *appliction `json:"application" yaml:"application" toml:"application"`
}

type appliction struct {
	Host   string `json:"host" yaml:"host" toml:"host"`
	Port   int    `json:"port" yaml:"port" toml:"port"`
	Domain string `json:"domain" yaml:"domain" toml:"domain"`

	server *gin.Engine
	lock   sync.Mutex
	root   gin.IRouter
}

// GinServer 方法返回一个 *gin.Engine 类型的实例
func (a *appliction) GinServer() *gin.Engine {
	// 加锁，防止并发访问
	a.lock.Lock()
	// 在函数结束时解锁
	defer a.lock.Unlock()

	// 如果 server 为空，则创建一个新的 *gin.Engine 实例
	if a.server == nil {
		a.server = gin.Default()
		// 使用 cors 中间件
		a.server.Use(cors.Default())
	}
	// 返回 server 实例
	return a.server
}

// GinRootRouter 函数返回一个gin.IRouter类型的值，该值是appliction结构体的一个成员变量root的值
func (a *appliction) GinRootRouter() gin.IRouter {
	// 调用GinServer函数，返回一个gin.IRouter类型的值
	r := a.GinServer()
	// 如果root为nil，则将r赋值给root
	if a.root == nil {
		a.root = r.Group("vblog").Group("api").Group("v1")
	}
	// 返回root的值
	return a.root
}

// 定义一个名为address的方法，返回一个字符串
func (a *appliction) address() string {
	// 使用fmt.Sprintf函数将a.Host和a.Port拼接成一个字符串
	return fmt.Sprintf("%s:%d", a.Host, a.Port)
}

// Start函数用于启动应用程序
func (a *appliction) Start() error {
	// 调用GinServer函数获取Gin服务器实例
	r := a.GinServer()
	// 运行Gin服务器，并返回错误信息
	return r.Run(a.address())
}

type mySQL struct {
	Host     string `json:"host" yaml:"host" toml:"host" env:"DATASOURCE_HOST"`
	Port     int    `json:"port" yaml:"port" toml:"port" env:"DATASOURCE_PORT"`
	DB       string `json:"database" yaml:"database" toml:"database" env:"DATASOURCE_DB"`
	Username string `json:"username" yaml:"username" toml:"username" env:"DATASOURCE_USERNAME"`
	Password string `json:"password" yaml:"password" toml:"password" env:"DATASOURCE_PASSWORD"`
	Debug    bool   `json:"debug" yaml:"debug" toml:"debug" env:"DATASOURCE_DEBUG"`

	db   *gorm.DB
	lock sync.Mutex
}

func (m *mySQL) DSN() string {
	return fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local",
		m.Username,
		m.Password,
		m.Host,
		m.Port,
		m.DB,
	)
}

func (m *mySQL) GetDB() *gorm.DB {
	m.lock.Lock()
	defer m.lock.Unlock()

	if m.db == nil {
		db, err := gorm.Open(mysql.Open(m.DSN()), &gorm.Config{})
		if err != nil {
			panic(err)
		}

		m.db = db

		if m.Debug {
			m.db = db.Debug()
		}
	}
	return m.db
}
